package com.xiyi.shouxin.dao;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.data.domain.Sort;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;

import com.xiyi.shouxin.exception.CommonException;
import com.xiyi.shouxin.exception.ErrorCode;

public class BaseRepository<T> {
    @Autowired
    protected JdbcTemplate template;
    protected JdbcPreparedStatement<T> stat;

    public Long create(T t) throws Exception {
        if (t == null) {
            throw new CommonException(ErrorCode.INVALIDPARAMTER);
        }

        KeyHolder keyHolder = new GeneratedKeyHolder();
        template.update(stat.genertateCreateSql(t), keyHolder);
        Long id = null;
        Number key = keyHolder.getKey();
        if (key != null) {
            id = key.longValue();
        }
        return id;
    }

    public void update(Long id, T t) throws Exception {
        if (id == null || t == null) {
            throw new CommonException(ErrorCode.INVALIDPARAMTER);
        }

        template.update(stat.genertateUpdateByIdSql(id, t));
    }

    public void delById(Long id) throws CommonException {
        if (id == null) {
            throw new CommonException(ErrorCode.INVALIDPARAMTER);
        }
        StringBuilder sb = new StringBuilder("DELETE FROM ");
        sb.append(stat.GetTableName());
        sb.append(" WHERE id = ?");
        template.update(sb.toString(), id);
    }

    public void delByIds(Collection<Long> ids) throws CommonException {
        if (ids.isEmpty()) {
            throw new CommonException(ErrorCode.INVALIDPARAMTER);
        }
        StringBuilder sb = new StringBuilder("DELETE FROM ");
        sb.append(stat.GetTableName());
        sb.append(" WHERE id IN ( ");
        List<String> els = new ArrayList<>();
        ids.forEach(id -> els.add("?"));
        sb.append(String.join(",", els));
        sb.append(" )");
        template.update(sb.toString(), ids.toArray());
    }

    public T findById(Long id, RowMapper<T> mapper) throws Exception {
        if (id == null || mapper == null) {
            throw new CommonException(ErrorCode.INVALIDPARAMTER);
        }
        StringBuilder sb = new StringBuilder("SELECT ");
        sb.append(stat.GetQueryColumns());
        sb.append(" FROM ");
        sb.append(stat.GetTableName());
        sb.append(" WHERE id = ? LIMIT 1");
        try {
            T t = template.queryForObject(sb.toString(), new Object[] { id }, mapper);
            return t;
        } catch (EmptyResultDataAccessException e) {

        }
        return null;
    }

    public List<T> findAllById(Collection<Long> ids, RowMapper<T> mapper) throws Exception {
        if (ids == null || ids.isEmpty() || mapper == null) {
            throw new CommonException(ErrorCode.INVALIDPARAMTER);
        }
        StringBuilder sb = new StringBuilder("SELECT ");
        sb.append(stat.GetQueryColumns());
        sb.append(" FROM ");
        sb.append(stat.GetTableName());
        sb.append(" WHERE id IN ( ");
        List<String> els = new ArrayList<>();
        ids.forEach(id -> els.add("?"));
        sb.append(String.join(",", els));
        sb.append(" )");
        return template.query(sb.toString(), mapper, ids.toArray());
    }

    public List<T> findAll(RowMapper<T> mapper) throws Exception {
        if (mapper == null) {
            throw new CommonException(ErrorCode.INVALIDPARAMTER);
        }
        StringBuilder sb = new StringBuilder("SELECT ");
        sb.append(stat.GetQueryColumns());
        sb.append(" FROM ");
        sb.append(stat.GetTableName());
        return template.query(sb.toString(), mapper);
    }

    protected List<T> findByMultiConditionsByPage(List<String> conditions, List<Object> args, Sort sort, int page,
            int size, RowMapper<T> mapper) throws Exception {
        if (mapper == null) {
            throw new CommonException(ErrorCode.INVALIDPARAMTER);
        }
        StringBuilder sb = new StringBuilder("SELECT ");
        sb.append(stat.GetQueryColumns());
        sb.append(" FROM ");
        sb.append(stat.GetTableName());

        if (!conditions.isEmpty()) {
            sb.append(" WHERE ");
            for (int i = 0; i < conditions.size(); i++) {
                String cond=conditions.get(i);
                cond="("+cond+")";
                conditions.set(i, cond);
            }
            sb.append(String.join(" AND ", conditions));
        }
        sb.append(" ORDER BY ");
        sb.append(sort.toString().replaceAll(":", " "));
        if (args == null) {
            args = new ArrayList<>();
        }
        sb.append(" LIMIT ? ");
        args.add(size);
        sb.append(" OFFSET ? ");
        args.add(page < 1 ? 0 : (page - 1) * size);
        return template.query(sb.toString(), args.toArray(), mapper);
    }

    protected int countByMultiConditions(List<String> conditions, List<Object> args) {
        StringBuilder sb = new StringBuilder("SELECT COUNT(1) ");
        sb.append(" FROM ");
        sb.append(stat.GetTableName());
        if (!conditions.isEmpty()) {
            sb.append(" WHERE ");
            for (int i = 0; i < conditions.size(); i++) {
                String cond=conditions.get(i);
                cond="("+cond+")";
                conditions.set(i, cond);
            }
            sb.append(String.join(" AND ", conditions));
        }
        return template.queryForObject(sb.toString(), args.toArray(), Integer.class);
    }
}
